根据对MODBUS TCP跟RTU之间通讯协议封装后写了一个通讯的DEMO例子,界面是参考的HSL软件的布局,主要是针对线圈寄存器和保存寄存器的多读写。 主要的功能:
MODBUS TCP/RUT两种通讯方式BOOL类型线圈寄存器的多读写保存寄存器各种数据类型的写入读取通讯时发送和读取到的字节数据日志
主要逻辑: 首先是跟串口或者TCP通讯, 其次是数据类型的写入,根据不同数据类型的字节长度读取跟写入对应的寄存器长度。 目前主要是针对数据的写入跟读取做一个简单的DEMO,扩展可以在这个之上进行扩展业务逻辑 部分代码展示
public static RtuHelper Intance = new RtuHelper();
//实例化串口
public static SerialPort port = new SerialPort();
//实例SOCKET
public Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) { SendTimeout = 300, ReceiveTimeout = 1000 };
private Int16 SendNum = 0;
//委托
public delegate void ReceiveData(object str);
public static event ReceiveData DataLog;
//打开串口配置串口
public static void SerialClass(ComClass p)
{
port.PortName = p.PortName;
port.BaudRate = p.BaudRate;
port.DataBits = p.Databit;
switch (p.Stopbit)
{
case 1:
port.StopBits = StopBits.One; //使用一个停止位
break;
case 1.5f:
port.StopBits = StopBits.OnePointFive; //使用一个停止位
break;
case 2:
port.StopBits = StopBits.Two; //使用一个停止位
break;
default:
break;
}
switch (p.Paritybit)
{
case "NONE":
port.Parity = Parity.None;
break;
case "ODD":
port.Parity = Parity.Odd;
break;
case "EVEN":
port.Parity = Parity.Even;
break;
case "MARK":
port.Parity = Parity.Mark;
break;
case "SPACE":
port.Parity = Parity.Space;
break;
default:
break;
}
//port.Handshake = Handshake.None;
port.RtsEnable = true;
port.DtrEnable = true;//获取或设置一个值,改值在串行通讯过程中启用数据终端就绪(DTR)信号。
port.ReadTimeout = 2000;
}
///
/// 打开串口
///
///
public static bool OpenPart()
{
bool ok = false;
//如果串口是打开的,先关闭
if (port.IsOpen) port.Close();
try
{
//打开串口
port.Open();
ok = true;
}
catch (Exception Ex)
{
throw Ex;
}
return ok;
}
///
/// 关闭串口
///
public static void closePort()
{
if (port.IsOpen)
{
port.Close();
}
}
//关闭socket通讯
public void DisConnect()
{
socket.Disconnect(true);
}
//打开Socket通讯
public bool ReConnect(string IP, int Port)
{
try { IPAddress.Parse(IP); }
catch { return false; }
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) { SendTimeout = 300, ReceiveTimeout = 1000 };
socket.Connect(IPAddress.Parse(IP), Port);
// task.Wait(ConnTimeout);
return socket.Connected;
}
public List ReadBools(string addr, UInt16 count, ModbusType modbusType)
{
List rst = new List();
if (!Read(addr, count, ref rst, modbusType))
Console.WriteLine("ReadBools");
return rst;
}
public bool WriteBools(string addr, UInt16 count, List value, ModbusType modbusType)
{
return (Write(addr, count, value, modbusType));
}
private bool Read(string addr, UInt16 count, ref List rst, ModbusType modbusType)
{
//byte[]需要指定长度,不支持Linq
List command = new List();
ParseReadSend(addr, count, rst, ref command, modbusType);
byte[] Read = new byte[1024 * 1024];
int len = 0;
if (modbusType == ModbusType.RTU)
{
if (!SendRTU(command.ToArray(), ref Read))
return false;
//报文组成完成
}
else if (modbusType == ModbusType.TCP)
{
if (!SocketSend(command.ToArray(), ref len, ref Read))
return false;
}
if (!AnalysisData(Read, ref rst, count, modbusType))
return false;
return true;
}
private bool Write(string addr, UInt16 count, List rst, ModbusType modbusType)
{
//byte[]需要指定长度,不支持Linq
List command = new List();
ParseWriteSend(addr, count, rst, ref command, modbusType);
byte[] Read = new byte[1024 * 1024];
int len = 0;
if (modbusType == ModbusType.RTU)
{
if (!SendRTU(command.ToArray(), ref Read))
return false;
}
else if (modbusType == ModbusType.TCP)
{
if (!SocketSend(command.ToArray(), ref len, ref Read))
return false;
}
return true;
}
private bool SocketSend(byte[] array, ref int recvlen, ref byte[] ReadData)
{
if (!socket.Connected)
return false;
if (array.Length != socket.Send(array))
return false;
DataLog($"[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} ModbusTcp]:TCP 发送:" + BitConverter.ToString(array).Replace('-', ' ') + "\t\r");
recvlen = socket.Receive(ReadData);
ReadData = ReadData.Skip(0).Take(recvlen).ToArray();
DataLog($"[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} ModbusTcp]:TCP 接收:" + BitConverter.ToString(ReadData).Replace('-', ' ') + "\t\r");
SendNum++;
return true;
}
private bool SendRTU(byte[] SendData, ref byte[] ReadData)
{
if (!port.IsOpen)
return false;
port.Write(SendData, 0, SendData.Length);
DataLog($"[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} ModbusTcp]:Rtu 发送:" + BitConverter.ToString(SendData).Replace('-', ' ') + "\t\r");
Thread.Sleep(500);
//响应报文接收和解析
byte[] read = new byte[port.BytesToRead];
port.Read(read, 0, read.Length);
DataLog($"[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} ModbusTcp]:Rtu 接收:" + BitConverter.ToString(read).Replace('-', ' ') + "\t\r");
ReadData = read;
return true;
}
//CRC校验
static List CRC16(List value, ushort poly = 0xA001, ushort crcInit = 0xFFFF)
{
if (value == null || !value.Any())
{
throw new ArgumentException("");
}
//计算
ushort crc = crcInit;
for (int i = 0; i
crc = (crc & 1) != 0 ? (ushort)((crc >> 1) ^ poly) : (ushort)(crc >> 1);
}
}
byte hi = (byte)((crc & 0xFF00) >> 8);//高位置
byte lo = (byte)(crc & 0x00FF);//底位置
List buffer = new List();
buffer.AddRange(value);
buffer.Add(lo);
buffer.Add(hi);
return buffer;
}
|